package com.ruiyian.netty.nettyclientTask;

import com.ruiyian.common.constant.Constants;
import com.ruiyian.common.core.domain.entity.Point;
import com.ruiyian.common.core.redis.RedisCache;
import com.ruiyian.common.utils.jfinsUtil.AnalysisInfomationBoard;
import com.ruiyian.common.utils.jfinsUtil.FinsMessage;
import com.ruiyian.common.utils.jfinsUtil.FinsMessageUtils;
import com.ruiyian.common.utils.jfinsUtil.Hex;
import com.ruiyian.common.utils.spring.SpringUtils;
import com.ruiyian.project.equipment.service.FireFillWaterService;
import io.netty.channel.*;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author chong
 * @email 673426164@qq.com
 * @create 2021/2/4
 * Desc: netty客户端业务操作 定时任务
 */
@Slf4j
@ChannelHandler.Sharable
public class ClientHandlerTask extends ChannelInboundHandlerAdapter {
    private int nowIndex = 0; // 指针索引
    // 注入日志操作类
    private static RedisCache redisCache;
    private List<Point> data = null;
    private static FireFillWaterService fillWaterService;

    static {
        // 命令头
        redisCache = SpringUtils.getBean(RedisCache.class);
        fillWaterService = SpringUtils.getBean(FireFillWaterService.class);
    }

    /**
     * 初始化操作 获取对应参数
     */
    void setValue() {
        // 操作点位集合
        data = redisCache.getCacheList(Constants.POINTLISTTASK);
    }

    /**
     * 客户端接收plc消息
     * 业务逻辑
     *
     * @param ctx
     * @param msg
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        try {
            if (!msg.toString().contains(Hex.encodeHexStr(FinsMessage.FINS_HEADER_BYTE, false))) {
                return;
            }
            InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
            log.info(socketAddress.getHostString() + "接收到消息:{}", msg);
            String messageType = FinsMessageUtils.analysisMessage(msg);
            if (StringUtils.isBlank(messageType)) {
                return;
            }
            if (messageType.equals("handshakeMessage")) {
                log.info("握手成功");
                return;
            }
            this.setValue();
            Map<String, ChannelFuture> connectMap = NettyStarterTask.getConnectMap();
            // 发送预案的代码
            FinsMessage finsMessage = null;
            Object key = redisCache.getCacheObject(Constants.NOWINDEXTASK);
            nowIndex = Integer.parseInt(key.toString());
            Integer count = data.size();
            if (messageType.equals("readMessage")) {
                String value = null;
                if (data.get(nowIndex).getLength() == 1) {
                    if (msg.toString().length() > 64) {
                        value = Integer.valueOf(msg.toString().substring(60, 64), 16).toString();
                    } else {
                        value = Integer.valueOf(msg.toString().substring(60, msg.toString().length()), 16).toString();
                    }
                } else {
                    value = AnalysisInfomationBoard.getStringValue(msg, data.get(nowIndex).getEncoding());
                }
                List<Point> cacheList = redisCache.getCacheList(Constants.RETURNPOINTTASK);
                cacheList.add(new Point(data.get(nowIndex).getId(), value, data.get(nowIndex).getTunnelId(), data.get(nowIndex).getCode()));
                redisCache.deleteObject(Constants.RETURNPOINTTASK);
                redisCache.setCacheList(Constants.RETURNPOINTTASK, cacheList);
                nowIndex++;
                redisCache.getOpera().increment(Constants.NOWINDEXTASK); //自增
                if (count > nowIndex) {
                    if (data.get(nowIndex).getType().equals("0")) {
                        finsMessage = FinsMessageUtils.createReadFineMessage(data.get(nowIndex).getMemoryArea(), Integer.parseInt(data.get(nowIndex).getRegisterAddress()), data.get(nowIndex).getLength(), data.get(nowIndex).getServerPath(),Constants.DEFAULT_SA1_T);
                    } else {
                        finsMessage = FinsMessageUtils.createReadFineMessage(data.get(nowIndex).getMemoryArea(), Integer.parseInt(data.get(nowIndex).getRegisterAddress()), data.get(nowIndex).getBits(), data.get(nowIndex).getLength(), data.get(nowIndex).getServerPath(),Constants.DEFAULT_SA1_T);
                    }
                    ChannelFuture channelFuture = connectMap.get(data.get(nowIndex).getServerPath());
                    if (channelFuture != null) {
                         channelFuture.channel().writeAndFlush(finsMessage.toString()).sync();
                        return;
                    }

                } else {
                    cacheList = redisCache.getCacheList(Constants.RETURNPOINTTASK);
                    fillWaterService.saveBatch(cacheList);
                }
            }
            /*if (messageType.equals("writeMessage")) {
                // 写入点位
                Map<String, Object> map = new HashMap<>();
                map.put("operateType", ReturnType.WRITE.getCode());
                map.put("groupNum", redisCache.getCacheObject("groupNum"));
                map.put("tunnelId", redisCache.getCacheObject("tunnelId"));
                map.put("moduleId", redisCache.getCacheObject("moduleId"));
                map.put(AjaxResult.CODE_TAG, HttpStatus.SUCCESS);
                if (data != null && data.size() > 1) {
                    nowIndex = Integer.parseInt(redisCache.getCacheObject(Constants.NOWINDEX).toString());
                    if (nowIndex >= data.size()) {
                        MyChannelHandlerPool.channelGroup.writeAndFlush(new TextWebSocketFrame(JSON.stringify(map)));
                    } else {
                        if (data.get(nowIndex).getType().equals("0")) {
                            finsMessage = FinsMessageUtils.createWriteMessage(data.get(nowIndex).getMemoryArea(), Integer.parseInt(data.get(nowIndex).getRegisterAddress()), Integer.valueOf(data.get(nowIndex).getValue()), data.get(nowIndex).getServerPath());
                        } else {
                            // 位写入
                            finsMessage = FinsMessageUtils.createWriteMessage(data.get(nowIndex).getMemoryArea(), Integer.parseInt(data.get(nowIndex).getRegisterAddress()), data.get(nowIndex).getBits(), Integer.valueOf(data.get(nowIndex).getValue()), data.get(nowIndex).getServerPath());
                        }
                        ChannelFuture channelFuture = connectMap.get(data.get(nowIndex).getServerPath());
                        nowIndex++;
                        redisCache.getOpera().increment(Constants.NOWINDEX);
                        if (channelFuture != null) {
                            log.info("发送命令" + finsMessage.toString());
                            channelFuture.channel().writeAndFlush(finsMessage.toString()).sync();
                            return;
                        }
                    }
                } else {
                    MyChannelHandlerPool.channelGroup.writeAndFlush(new TextWebSocketFrame(JSON.stringify(map)));
                }
            }*/
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }



    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        ctx.close();
    }

    /**
     * 关闭连接
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        InetSocketAddress ipSocket = (InetSocketAddress) ctx.channel().remoteAddress();
        int port = ipSocket.getPort();
        String host = ipSocket.getHostString();
        log.error("客户端与设备" + host + ":" + port + "连接断开!");
        NettyStarterTask.setConnectRemove(host, port);
        ctx.channel().closeFuture().sync();
        ctx.close();
        final EventLoop eventLoop = ctx.channel().eventLoop();
        eventLoop.schedule(new Runnable() {
            @Override
            public void run() {
                NettyStarterTask.doConnect(host, port);
            }
        }, 5L, TimeUnit.SECONDS);
        super.channelInactive(ctx);
    }

    /**
     * 建立连接
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        InetSocketAddress ipSocket = (InetSocketAddress) ctx.channel().remoteAddress();
        int port = ipSocket.getPort();
        String host = ipSocket.getHostString();
        log.info("客户端与plc：" + host + ":" + port + "连接成功!");
        // 握手连接  udp 6e = 110
        FinsMessage finsMessage = new FinsMessage(Constants.DEFAULT_SA1_T);
        ctx.writeAndFlush(finsMessage.toString());
        NettyStarterTask.setConnect(host, port, ctx.channel().newSucceededFuture());
        super.channelActive(ctx);
//        ReferenceCountUtil.release(finsMessage);
//        定时心跳机制
//        this.channel = ctx.channel();
//        ping(ctx.channel());
    }

}
